﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.IO;
using System.Reflection;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Diagnostics;

namespace Ling.P2P.Provider
{
    public class TcpP2PServerEntry : TcpP2PEntry
    {
        public TcpP2PServerEntry()
        {
            //
        }

        /// <summary>
        /// 获取该实例的 P2PEntry 类型。
        /// </summary>
        public override P2PEntryType EntryType
        {
            get { return P2PEntryType.P2PServer; }
        }

        #region 服务端事件定义

        /// <summary>
        /// 当有客户端请求登入是触发。
        /// </summary>
        public event LogInStatusEventHandler ClientLogIn;

        /// <summary>
        /// 用于触发 ClientLogIn 事件。
        /// </summary>
        /// <param name="skt"></param>
        protected virtual void OnClientLogIn(Socket skt)
        {
            if (ClientLogIn != null)
                ClientLogIn(this, skt);
        }

        /// <summary>
        /// 当有客户端请求登出时触发。
        /// </summary>
        public event LogInStatusEventHandler ClientLogOut;

        /// <summary>
        /// 用于触发 ClientLogOut 事件。
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnClientLogOut(Socket skt)
        {
            if (ClientLogOut != null)
                ClientLogOut(this, skt);
        }

        /// <summary>
        /// 当有客户端请求状态维护时触发。
        /// </summary>
        public event LogInStatusEventHandler ClientMaintain;

        /// <summary>
        /// 用于触发 ClientMaintain 事件。
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnClientMaintain(Socket skt)
        {
            if (ClientMaintain != null)
                ClientMaintain(this, skt);
        }

        #endregion

        /// <summary>
        /// 启动该 P2PEntry 服务端。
        /// </summary>
        public void Start()
        {
            _LocalIpEndPoint = new IPEndPoint(LocalIP, LocalPort);
            ListenReceive();
        }

        /// <summary>
        /// 侦听程序收到数据时的处理。
        /// </summary>
        /// <param name="skt"></param>
        protected override void AcceptData(Socket skt)
        {
            byte[] data;
            switch (CurrentMessage.Value.MessageType)
            { 
                case P2PConstants.MSG_LOG_IN : // 登录入指令。
                    OnClientLogIn(skt);
                    break;
                case P2PConstants.MSG_LOG_OUT : // 登出指令。
                    OnClientLogOut(skt);
                    break;
                case P2PConstants.MSG_MAINTAIN_LOGIN : // 登入状态维护（客户端的NAT分配过时的时候靠它来实时更新）。
                    OnClientMaintain(skt);
                    break;
            }
        }

        /// <summary>
        /// 向特定的 Socket 发送消息。
        /// </summary>
        /// <param name="Message">要发送的消息。</param>
        /// <param name="skt">消息要送达的 Socket 对象。</param>
        public void SendMessage(P2PMessage Message, Socket skt)
        {
            byte[] msg_data = P2PMessageConverter.GetBytes(Message);
            byte[] data = new byte[msg_data.Length + 1];
            data[0] = P2PConstants.HEADER_IS_MSG;
            int dIndex = 1;
            for (int i = 0; i < msg_data.Length; ++i)
            {
                data[dIndex] = msg_data[i];
                dIndex++;
            }
            SendData(data, skt, false);
        }

        /// <summary>
        /// 向指定的 Socket 对象发送数据，并返回成功发送的字节数。
        /// </summary>
        /// <param name="data">要发送的数据。</param>
        /// <param name="skt">要发送到的 Socket 对象。</param>
        /// <returns></returns>
        public int SendData(byte[] data, Socket skt)
        {
            SendData(BitConverter.GetBytes(data.Length), skt, false); // 先发送文件长度。
            return SendData(data, skt, false); // 然后发送内容。
        }
    }
}
